package com.alibaba.citrus.ots.application.report.ability.facade.service;

import com.alibaba.citrus.ots.application.report.ability.repository.PlatformRepository;
import com.alibaba.citrus.ots.application.report.ability.utils.DomUtil;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.es.helper.ElasticSearchClientFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.*;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.BcOrderService;
import com.epoch.app.otsapplicationreportsdk.commercustomerplanreport.dto.PlatformCustomerGroupRequest;
import com.epoch.app.otsapplicationreportsdk.commercustomerplanreport.dto.PlatformCustomerGroupResponse;
import com.epoch.app.otsapplicationreportsdk.commercustomerplanreport.model.CommerCustomerPlanReport;
import com.epoch.app.otsapplicationreportsdk.commercustomerplanreport.service.CommerCustomerPlanReportService;
import com.epoch.app.otsapplicationreportsdk.contants.OtsApplicationReportSdkConstants;
import com.epoch.app.otsapplicationreportsdk.model.dto.LoadPlanReachCorrectionRequest;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.dto.QueryAllocateOrderDetailReportFtobRequest;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.model.OarsAllocateOrderDetailReportFtob;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftob.service.OarsAllocateOrderDetailReportFtobService;
import com.epoch.app.otsapplicationreportsdk.oarsallocateorderdetailreportftof1.service.OarsAllocateOrderDetailReportFtof1Service;
import com.epoch.app.otsapplicationreportsdk.planreachcorrection.model.PlanReachCorrection;
import com.epoch.app.otsapplicationreportsdk.planreachcorrectionreport.service.PlanReachCorrectionReportService;
import com.epoch.app.crunifiedinventory.sdo.enums.AllocateOrderTypeEnum;
import com.epoch.app.crunifiedinventory.service.CrUnifiedInventoryService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality;
import org.elasticsearch.search.aggregations.metrics.cardinality.CardinalityAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 电商_计划达成纠偏表 报表查询
 */
@Primary
@Component
public class PlanReachCorrectionReportServiceImpl implements PlanReachCorrectionReportService {
    public static final String CUSTOMER_COMMERCE_PLATFORM = "customer_commerce_platform";
    public static final String SUB_SC_ITEM_CODE = "sub_sc_item_code";
    public static final String MAIN_APPLY_ORG_ID = "main_apply_org_id";
    public static final String SUB_GMT_CREATE = "sub_gmt_create";
    public static final String KEYWORD = ".keyword";
    public static final String SHIP_WAREHOUSE_TYPE = "ship_warehouse_type";
    public static final String MAIN_IS_D_T_C = "main_is_d_t_c";
    public static final String MAIN_TYPE = "main_type";
    public static final String MAIN_CREATE_TIME = "main_create_time";
    public static final String SC_ITEM_TITLE = "sc_item_title";

    private static Log log = Log.getLogger(PlanReachCorrectionReportServiceImpl.class);

    public static final String ALLOCATE_ORDER_DETAIL_REPORT_FTOB = "allocate_order_detail_report_ftob";
    // ES 分组字段名称
    public static final String CARDINALITY_ITEM_PLATFORM = "cardinality_item_platform";
    //public static final String ES_CARDINALITY_GROUPBYID = "cardinality_groupbyid";
    // ES 分桶字段名称
    public static final String ES_BUCKET_FIELD = "bucket_field";


    //沙盒本地启动使用
  // @Resource(name = "restHighLevelClientSandbox")
  @Resource(name = "restHighLevelClient")
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private OarsAllocateOrderDetailReportFtobService oarsAllocateOrderDetailReportFtobService;

    @Resource
    OarsAllocateOrderDetailReportFtof1Service oarsAllocateOrderDetailReportFtof1Service;

    @Resource
    CommerCustomerPlanReportService commerCustomerPlanReportService;

    @Resource
    private BcOrderService bcOtsService;

    @Resource
    private CrUnifiedInventoryService otsUnifiedInventoryService;

    @Resource
    private PlatformRepository platformRepository;


    @Override
    @FacadeInvoker
    public Result<List<PlanReachCorrection>> loadPlanReachCorrectionForPage(LoadPlanReachCorrectionRequest loadPlanReachCorrectionRequest) {
        log.info("计划达成入参：" + JSONObject.toJSONString(loadPlanReachCorrectionRequest));

        // 查询 1900021273 收货组织下的
        OrganizationSDO organizationSDO = allocateOrderByCode("1900021273");
        if (ObjectUtils.isEmpty(organizationSDO)) {
            return Result.listSuccess(new ArrayList<>(), 0);
        }

        //platformCode-platformId
        HashMap<String, String> codeIdMap = new HashMap<>();
        //platformId-platformCode
        Map<String, String> platformIdCodeMap = platformRepository.geAllPlatformIdCodeMap();
        //platformId-platformCode
        Map<String, String> platformIdNameMap = platformRepository.geAllPlatformIdNameMap();
        //platform code collect
        List<String> combinationPlatCodes = new ArrayList<>();
        //platform id collect
//        List<String> combinationPlatIds = new ArrayList<>();
        //item out code collect
        List<String> combinationItemOutIds = new ArrayList<>();
        //item id set
        Set<String> itemIds = new HashSet<>();

        //item out code map,buffer itemId->itemName
        Map<String, String> itemOutIdNameMap;
        //item out id collect,for query input params of method @getEfficientPlatGoodsCombination
        List<String> outItemIds = new ArrayList<>();

        // default now day
        if (CollectionUtils.isEmpty(loadPlanReachCorrectionRequest.getTime())) {
            loadPlanReachCorrectionRequest.setTime(Arrays.asList(DateUtils.toDateStr(DateUtils.getFirstTime(new Date()), DateUtils.DATETIME_FORMAT),
                    DateUtils.toDateStr(DateUtils.getLatestTime(new Date()), DateUtils.DATETIME_FORMAT)));
        } else {
            // can not cross month
            Date start = DateUtils.parse(loadPlanReachCorrectionRequest.getTime().get(0));
            Date end = DateUtils.parse(loadPlanReachCorrectionRequest.getTime().get(1));
            if (!equalsMonth(start, end)) {
                return Result.fail("", "查询日期不能跨月");
            }
        }

        // If the query conditions are not passed on the e-commerce platform, then query all e-commerce platforms
        if (org.apache.commons.collections.CollectionUtils.isEmpty(loadPlanReachCorrectionRequest.getPlatformCodes())) {
            loadPlanReachCorrectionRequest.setPlatformCodes(new ArrayList(platformRepository.getWarehouseByPlatFormCodes()));
        }

        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(loadPlanReachCorrectionRequest.getGoodsId())) {
            outItemIds = getOutItemIds(loadPlanReachCorrectionRequest.getGoodsId());
            itemIds = new HashSet<>(loadPlanReachCorrectionRequest.getGoodsId());
        }

        //get efficient combination of platformCode -->outScItemId ,and total,for page --------expired demand
        //get efficient combination of platformCode -->outScItemId ,and total,all of them
        Result<List<Pair<String, String>>> efficientPlatGoodsCombination = getEfficientPlatGoodsCombination(platformCodesById(loadPlanReachCorrectionRequest.getPlatformCodes(), codeIdMap),
                outItemIds, loadPlanReachCorrectionRequest.getTime(), organizationSDO.getId(),loadPlanReachCorrectionRequest.getGoodsName());

        //query platform is null ,sc item Pair
        Result<List<Pair<String, String>>> emptyPlatGoodsCombination=new Result<>();
        if (loadPlanReachCorrectionRequest.getPlatformCodes().contains(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())){
            emptyPlatGoodsCombination= getEmptyPlatGoodsCombination(platformCodesById(loadPlanReachCorrectionRequest.getPlatformCodes(), codeIdMap),
                    outItemIds, loadPlanReachCorrectionRequest.getTime(), organizationSDO.getId(), loadPlanReachCorrectionRequest.getGoodsName());
        }

        // Inquire about the monthly plan
        PlatformCustomerGroupRequest platformCustomerGroupRequest = coverPlatformCustomerGroupRequest(loadPlanReachCorrectionRequest, outItemIds);
        log.info("Inquire about monthly plan participation：" + JSONObject.toJSONString(platformCustomerGroupRequest));
        PlatformCustomerGroupResponse pageResultResult = commerCustomerPlanReportService.platformCustomerGroup(platformCustomerGroupRequest);
        log.info("Query monthly plan results：" + JSONObject.toJSONString(pageResultResult));
        //for null platform sales plan ,default 999999 as code
        Map<String, List<CommerCustomerPlanReport>> salePlanPlatFormScMap = Nullable.stream(pageResultResult.getResult()).
                collect(Collectors.groupingBy(o -> (null==platformIdCodeMap.get(o.getPlatformCode()))?OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID():platformIdCodeMap.get(o.getPlatformCode())));

        //sales plan all platformCode ->scItemOutId Pair list,for page
        List<Pair<String, String>> planPlatformScPairList = new ArrayList<>();
        for (Map.Entry<String, List<CommerCustomerPlanReport>> planPlatformScEntry : salePlanPlatFormScMap.entrySet()) {
            if (CollectionUtils.isNotEmpty(planPlatformScEntry.getValue())) {
                for (CommerCustomerPlanReport commerCustomerPlanReport : planPlatformScEntry.getValue()) {
                    planPlatformScPairList.add(Pair.of(planPlatformScEntry.getKey(), commerCustomerPlanReport.getOuterId()));
                }
            }

        }
//        for (Map.Entry<String, String> planPlatformScEntry : salePlanPlatFormScMap.entrySet()) {
//            planPlatformScPairList.add(Pair.of(planPlatformScEntry.getKey(),planPlatformScEntry.getValue()));
//        }
        Map<String, List<CommerCustomerPlanReport>> salePlanMap = Nullable.stream(pageResultResult.getResult()).collect(Collectors.groupingBy(o -> o.getPlatformCode() + "-" + o.getOuterId()));

        if ((Objects.isNull(efficientPlatGoodsCombination) || CollectionUtils.isEmpty(efficientPlatGoodsCombination.getResult())) &&
                (Objects.isNull(emptyPlatGoodsCombination) || CollectionUtils.isEmpty(emptyPlatGoodsCombination.getResult()))&&
                CollectionUtils.isEmpty(planPlatformScPairList)) {
            return Result.success(new ArrayList<>());
        }

        //merge factory  and salesPlan platformCode->outId combinate
        List<Pair<String, String>> total = new ArrayList<>();
        if (Objects.nonNull(efficientPlatGoodsCombination) && CollectionUtils.isNotEmpty(efficientPlatGoodsCombination.getResult())) {
            total.addAll(efficientPlatGoodsCombination.getResult());
        }
        if (Objects.nonNull(emptyPlatGoodsCombination) && CollectionUtils.isNotEmpty(emptyPlatGoodsCombination.getResult())) {
            total.addAll(emptyPlatGoodsCombination.getResult());
        }
        if (CollectionUtils.isNotEmpty(planPlatformScPairList)) {
            total.addAll(planPlatformScPairList);
        }

        //distinct and sort,Pair equals will compare key&value
        total = total.stream().distinct().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList());


        int limit = loadPlanReachCorrectionRequest.getLimit();
        int start = loadPlanReachCorrectionRequest.getStart();
        limit = Math.min(total.size(), limit + start);
        List<Pair<String, String>> pageResult = total.subList(start, limit);

        for (Pair<String, String> pair : pageResult) {
            combinationPlatCodes.add(pair.getKey());
            combinationItemOutIds.add(pair.getValue());
//            combinationPlatIds.add(codeIdMap.get(pair.getKey()));
        }


        // 获取 上旬天数 中旬天数 下旬天数
        // Get the number of days in the first ten days, the number of days in the middle ten days, the number of days in the last ten days
        List<Integer> days = getDays(loadPlanReachCorrectionRequest.getTime());
        int fistDays = days.get(0);
        int middleDays = days.get(1);
        int lastDays = days.get(2);

        combinationPlatCodes = combinationPlatCodes.stream().distinct().collect(Collectors.toList());
        // key(平台-货品)->工厂直发订单数量
        Map<String, Integer> factorySendOrder = getFactorySendOrder(combinationPlatCodes, combinationItemOutIds, loadPlanReachCorrectionRequest.getTime(), itemIds);

        // key平台id->平台名称
      //  Map<String, String> platformNameById = platformNameById(new ArrayList<>(combinationPlatIds));

        List<PlanReachCorrection> list = new ArrayList<>();

        itemOutIdNameMap = getOutItemNamesByCodes(new ArrayList<>(combinationItemOutIds));

        for (Pair<String, String> pair : pageResult) {
            String platformCode = pair.getKey();
            String itemOutId = pair.getValue();
            String platformId = codeIdMap.get(platformCode);
            String key = platformId + "-" + itemOutId;
            String scItemName = itemOutIdNameMap.get(itemOutId);
            CommerCustomerPlanReport monthlyCommerceSDO = CollectionUtils.isNotEmpty(salePlanMap.get(key)) ? salePlanMap.get(key).get(0) : new CommerCustomerPlanReport();
            PlanReachCorrection planReachCorrection = coverPlanReachCorrection(loadPlanReachCorrectionRequest.getTime().get(0), fistDays, middleDays, lastDays, monthlyCommerceSDO, factorySendOrder, platformIdNameMap, loadPlanReachCorrectionRequest.getIsExcel(), platformCode, platformId, itemOutId, scItemName);
            list.add(planReachCorrection);
        }

        return Result.listSuccess(list, total.size());
    }

    /**
     * 获取 平台id：平台名称
     *
     * @param platformIds
     * @return
     */
    public Map<String, String> platformNameById(List<String> platformIds) {
        int start = 0;
        int limit = 100;
        // 分页查询 电商平台
        ListPlatformPageReportRequest reportRequest = ListPlatformPageReportRequest.builder()
                .start(start)
                .limit(limit)
                .platformIds(platformIds).build();
        log.info("查询电商平台入参：" + JSONObject.toJSONString(reportRequest));
        ListPlatformPageReportResponse listPlatformPageReportResponse = bcOtsService.listPlatformPageReport(reportRequest);
        log.info("查询电商平台结果：" + JSONObject.toJSONString(reportRequest));
        int allPage = listPlatformPageReportResponse.getTotal() / limit;
        if (listPlatformPageReportResponse.getTotal() % limit > 0) {
            allPage += 1;
        }

        if (ObjectUtils.isEmpty(listPlatformPageReportResponse)) {
            return new HashMap<>();
        }
        List result = listPlatformPageReportResponse.getResult();
        if (CollectionUtils.isEmpty(result)) {
            return new HashMap<>();
        }

        for (int i = 1; i < allPage; i++) {
            start = limit * i;
            ListPlatformPageReportRequest reportRequest1 = ListPlatformPageReportRequest.builder()
                    .start(start)
                    .limit(limit)
                    .platformIds(platformIds).build();
            ListPlatformPageReportResponse listPlatformPageReportResponse1 = bcOtsService.listPlatformPageReport(reportRequest1);
            if (!ObjectUtils.isEmpty(listPlatformPageReportResponse1) && !CollectionUtils.isEmpty(listPlatformPageReportResponse1.getResult())) {
                result.addAll(listPlatformPageReportResponse1.getResult());
            }
        }

        Map<String, String> map = new HashMap<>();
        result.forEach(o -> {
            Map map1 = (Map) o;
            map.put(map1.get("platformId").toString(), map1.get("platformName").toString());
        });
        return map;
    }

    /**
     * 平台-货品 工厂直发订单数量
     *
     * @param
     * @param
     * @param goodIds
     * @param time
     * @param itemIds
     * @return
     */
    public Map<String, Integer> getFactorySendOrder(List<String> platFormCodes, List<String> goodIds, List<String> time, Set<String> itemIds) {
        // 电商平台-货品id:工厂直发订单数量
        Map<String, Integer> map = new HashMap<>();

        // 查询 1900021273 收货组织下的
        OrganizationSDO organizationSDO = allocateOrderByCode("1900021273");
        if (ObjectUtils.isEmpty(organizationSDO)) {
            return map;
        }

        // 两个加起来
        List<OarsAllocateOrderDetailReportFtob> list = new ArrayList<>();

        // F->b调拨单
        int startb = 0;
        int limitb = 500;

        QueryAllocateOrderDetailReportFtobRequest request = QueryAllocateOrderDetailReportFtobRequest.builder()
                .platformNullId(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())
                .type(AllocateOrderTypeEnum.HEADQUARTER_SALES.getType())
                .isDTC(1)
                .applyOrgIds(Collections.singletonList(organizationSDO.getId()))
                .platformIds(platFormCodes)
                .scItemOuterIds(goodIds)
                .warehouseTypes(Arrays.asList(2, 5))
                .startTime(DateUtils.getFirstTime(DateUtils.toDateStr(DateUtils.parse(time.get(0)), DateUtils.DATETIME_FORMAT)))
                .endTime(DateUtils.getLastTime(DateUtils.toDateStr(DateUtils.parse(time.get(1)), DateUtils.DATETIME_FORMAT)))
                .start(startb).limit(limitb).build();
        log.info("查询F->b调拨单入参：" + JSONObject.toJSONString(request));
        // 查询 这段时间内 这些商品的 的调拨单
        Result<List<OarsAllocateOrderDetailReportFtob>> listResultFtob = oarsAllocateOrderDetailReportFtobService.queryAllocateOrderDetailReportFtob(request);
        log.info("查询F->b调拨单结果：" + JSONObject.toJSONString(listResultFtob));
        int allPage = listResultFtob.getTotal() / limitb;
        if (listResultFtob.getTotal() % limitb > 0) {
            allPage += 1;
        }
        if (!ObjectUtils.isEmpty(listResultFtob) && !CollectionUtils.isEmpty(listResultFtob.getResult())) {
            list = listResultFtob.getResult();
        } else {
            log.info("没有符合要求的F->b调拨单，入参：{}", JSON.toJSONString(request));
        }
        for (int i = 1; i < allPage; i++) {
            startb = limitb * i;
            request.setStart(startb);
            // 查询 这段时间内 这些商品的 的调拨单
            Result<List<OarsAllocateOrderDetailReportFtob>> listResult1 = oarsAllocateOrderDetailReportFtobService.queryAllocateOrderDetailReportFtob(request);
            if (!ObjectUtils.isEmpty(listResult1) && !ObjectUtils.isEmpty(listResult1.getResult())) {
                list.addAll(listResult1.getResult());
            }
        }

        // 把查询结果中 平台code 转为平台id
        // Map<String, String> codeByIdMap = platformCodeByIdMap(platFormIds);
        list.forEach(orderDetailReportFtob -> {
            itemIds.add(orderDetailReportFtob.getSubScItemId());
            //itemOutIdNameMap.put(orderDetailReportFtob.getSubScItemCode(),orderDetailReportFtob.getScItemTitle());
            String customerCommercePlatform = orderDetailReportFtob.getCustomerCommercePlatform();
            if (!StringUtils.isEmpty(customerCommercePlatform)) {
                //String platformId = codeByIdMap.get(customerCommercePlatform);
                // if (!StringUtils.isEmpty(platformId)) {
                orderDetailReportFtob.setCustomerCommercePlatform(customerCommercePlatform);
                // }
            }
        });

        list.forEach(orderDetailReportFtob -> {
            // 订单数量
            Integer quantity = StringUtils.isEmpty(orderDetailReportFtob.getSubQuantity()) ? 0 : new BigDecimal(orderDetailReportFtob.getSubQuantity()).intValue();
            // 发货数量
            Integer shipQuantity = StringUtils.isEmpty(orderDetailReportFtob.getSubShipQuantity()) ? 0 : orderDetailReportFtob.getSubShipQuantity().intValue();
            // 收货数量
            Integer receiveQuantity = StringUtils.isEmpty(orderDetailReportFtob.getSubReceiveQuantity()) ? 0 : orderDetailReportFtob.getSubReceiveQuantity().intValue();

            // 最终该单的 工厂直发订单数量
            Integer finalNum = quantity;

            if (!ObjectUtils.isEmpty(orderDetailReportFtob.getMainReturnOrder()) && orderDetailReportFtob.getMainReturnOrder() == 1) {
                // 退单计算
                //仅行关闭 关闭取收货数量
                //无退单无行关闭，收货数量>订单数量 订单数量和收货数量哪个大取哪个
                //无退单无行关闭，收货数量<订单数量 订单数量和收货数量哪个大取哪个
                if (orderDetailReportFtob.getSubClose() != null && orderDetailReportFtob.getSubClose() == 1) {
                    // 关闭 取收货数量
                    finalNum = receiveQuantity * -1;
                } else {
                    // 如果没有 关闭 收货数量大取收货数量，订单数量大取订单数量
                    if (receiveQuantity.compareTo(quantity) > 0) {
                        finalNum = receiveQuantity * -1;
                    } else {
                        finalNum = quantity * -1;
                    }
                }
            } else {
                // 正向单计算
                //仅行关闭 关闭取发货数量
                //无退单无行关闭，发货数量>订单数量 订单数量和发货数量哪个大取哪个
                //无退单无行关闭，发货数量<订单数量 订单数量和发货数量哪个大取哪个
                if (orderDetailReportFtob.getSubClose() != null && orderDetailReportFtob.getSubClose() == 1) {
                    // 关闭 取发货数量
                    finalNum = shipQuantity;
                } else {
                    // 如果没有 关闭 发货数量大取发货数量，订单数量大取订单数量
                    if (shipQuantity.compareTo(quantity) > 0) {
                        finalNum = shipQuantity;
                    }
                }
            }

            String platformId = StringUtils.isEmpty(orderDetailReportFtob.getCustomerCommercePlatform()) ? OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID() : orderDetailReportFtob.getCustomerCommercePlatform();
            String key1 = platformId + "-" + orderDetailReportFtob.getSubScItemCode();


            Integer value = map.get(key1);
            if (value != null) {
                value = value + finalNum;
            } else {
                value = finalNum;
            }
            map.put(key1, value);
        });

        return map;
    }

    /**
     * 获取 平台code：平台id
     *
     * @param platformIds
     * @return
     */
    public Map<String, String> platformCodeByIdMap(List<String> platformIds) {
        int start = 0;
        int limit = 100;
        // 分页查询 电商平台
        ListPlatformPageReportRequest reportRequest = ListPlatformPageReportRequest.builder()
                .start(start)
                .limit(limit)
                .platformIds(platformIds).build();
        log.info("查询电商平台入参：" + JSONObject.toJSONString(reportRequest));
        ListPlatformPageReportResponse listPlatformPageReportResponse = bcOtsService.listPlatformPageReport(reportRequest);
        log.info("查询电商平台结果：" + JSONObject.toJSONString(reportRequest));
        int allPage = listPlatformPageReportResponse.getTotal() / limit;
        if (listPlatformPageReportResponse.getTotal() % limit > 0) {
            allPage += 1;
        }

        if (ObjectUtils.isEmpty(listPlatformPageReportResponse)) {
            return new HashMap<>();
        }
        List result = listPlatformPageReportResponse.getResult();
        if (CollectionUtils.isEmpty(result)) {
            return new HashMap<>();
        }

        for (int i = 1; i < allPage; i++) {
            start = limit * i;
            ListPlatformPageReportRequest reportRequest1 = ListPlatformPageReportRequest.builder()
                    .start(start)
                    .limit(limit)
                    .platformIds(platformIds).build();
            ListPlatformPageReportResponse listPlatformPageReportResponse1 = bcOtsService.listPlatformPageReport(reportRequest1);
            if (!ObjectUtils.isEmpty(listPlatformPageReportResponse1) && !CollectionUtils.isEmpty(listPlatformPageReportResponse1.getResult())) {
                result.addAll(listPlatformPageReportResponse1.getResult());
            }
        }

        Map<String, String> map = new HashMap<>();
        result.forEach(o -> {
            Map map1 = (Map) o;
            map.put(map1.get("platformCode").toString(), map1.get("platformId").toString());
        });
        return map;
    }

    /**
     * 获取 平台id转平台code 集合
     *
     * @param platformIds
     * @param codeIdMap
     * @return
     */
    public List<String> platformCodesById(List<String> platformIds, HashMap<String, String> codeIdMap) {

        // 如果 查询条件只有其他电商平台 则不需要转code
        if (platformIds.contains(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())
                && platformIds.size() == 1) {
            return new ArrayList<String>() {{
                add(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());
            }};
        }

        int start = 0;
        int limit = 100;
        // 分页查询 电商平台
        ListPlatformPageReportRequest reportRequest = ListPlatformPageReportRequest.builder()
                .start(start)
                .limit(limit)
                .platformIds(platformIds).build();
        log.info("查询电商平台入参：" + JSONObject.toJSONString(reportRequest));
        ListPlatformPageReportResponse listPlatformPageReportResponse = bcOtsService.listPlatformPageReport(reportRequest);
        log.info("查询电商平台结果：" + JSONObject.toJSONString(reportRequest));
        int allPage = listPlatformPageReportResponse.getTotal() / limit;
        if (listPlatformPageReportResponse.getTotal() % limit > 0) {
            allPage += 1;
        }

        if (ObjectUtils.isEmpty(listPlatformPageReportResponse)) {
            return new ArrayList<>();
        }
        List result = listPlatformPageReportResponse.getResult();
        if (CollectionUtils.isEmpty(result)) {
            return new ArrayList<>();
        }

        for (int i = 1; i < allPage; i++) {
            start = limit * i;
            ListPlatformPageReportRequest reportRequest1 = ListPlatformPageReportRequest.builder()
                    .start(start)
                    .limit(limit)
                    .platformIds(platformIds).build();
            ListPlatformPageReportResponse listPlatformPageReportResponse1 = bcOtsService.listPlatformPageReport(reportRequest1);
            if (!ObjectUtils.isEmpty(listPlatformPageReportResponse1) && !CollectionUtils.isEmpty(listPlatformPageReportResponse1.getResult())) {
                result.addAll(listPlatformPageReportResponse1.getResult());
            }
        }

        List<String> list = new ArrayList<>();
        result.forEach(o -> {
            Map map1 = (Map) o;
            list.add(map1.get("platformCode").toString());
            codeIdMap.put(map1.get("platformCode").toString(), map1.get("platformId").toString());
        });

        if (platformIds.contains(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())) {
            list.add(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());
            codeIdMap.put(null, OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());
        }
        return list;
    }

    /**
     * 获取 上中下旬 天数
     *
     * @param time
     * @return
     */
    public List<Integer> getDays(List<String> time) {
        Date date = new Date();
        int fistDays = 0;
        int middleDays = 0;
        int lastDays = 0;
        if (!CollectionUtils.isEmpty(time)) {
            Date startDay = DateUtils.parse(time.get(0));
            Date endDay = DateUtils.parse(time.get(1));

            if (startDay.before(DomUtil.getDate(11, time.get(0)))) {
                if (endDay.before(DomUtil.getDate(11, time.get(0)))) {
                    // 获取 开始时间 - 结束时间 上旬天数
                    fistDays = DomUtil.getBetweenDays(time.get(0), time.get(1));
                } else if (endDay.before(DomUtil.getDate(21, time.get(0)))) {
                    // 获取 开始时间 - 上旬结束 上旬天数
                    fistDays = DomUtil.getBetweenDays(DateUtils.formatDate(startDay, DateUtils.DATETIME_FORMAT), DomUtil.getDayStr(10, time.get(1)));
                    // 获取 中旬开始 - 结束时间 中旬天数
                    middleDays = DomUtil.getBetweenDays(DomUtil.getDayStr(11, time.get(1)), time.get(1));
                } else {
                    // 获取 开始时间 - 上旬结束 上旬天数
                    fistDays = DomUtil.getBetweenDays(DateUtils.formatDate(startDay, DateUtils.DATETIME_FORMAT), DomUtil.getDayStr(10, time.get(1)));
                    // 获取 中旬开始 - 结束时间 中旬天数
                    middleDays = DomUtil.getBetweenDays(DomUtil.getDayStr(11, time.get(1)), DomUtil.getDayStr(20, time.get(1)));
                    // 获取 下旬开始 - 结束时间 下旬天数
                    lastDays = DomUtil.getBetweenDays(DomUtil.getDayStr(21, time.get(1)), time.get(1));
                }
            } else if (startDay.before(DomUtil.getDate(21, time.get(0)))) {
                if (endDay.before(DomUtil.getDate(21, time.get(0)))) {
                    // 获取 开始时间 - 中旬结束 中旬天数
                    middleDays = DomUtil.getBetweenDays(time.get(0), time.get(1));
                } else {
                    // 获取 开始时间 - 中旬结束 中旬天数
                    middleDays = DomUtil.getBetweenDays(time.get(0), DomUtil.getDayStr(20, time.get(1)));
                    // 获取 下旬开始 - 结束时间 下旬天数
                    lastDays = DomUtil.getBetweenDays(DomUtil.getDayStr(21, time.get(1)), time.get(1));
                }
            } else {
                // 获取 开始时间 - 结束时间 下旬天数
                lastDays = DomUtil.getBetweenDays(time.get(0), time.get(1));
            }

        } else {
            if (date.before(DomUtil.getDate(11, time.get(0)))) {
                fistDays = 1;
            } else if (date.before(DomUtil.getDate(21, time.get(0)))) {
                middleDays = 1;
            } else {
                lastDays = 1;
            }
        }

        return Arrays.asList(fistDays, middleDays, lastDays);
    }


    /**
     * 根据 code 查询 组织
     *
     * @param code
     * @return
     */
    public OrganizationSDO allocateOrderByCode(String code) {
        BaselineGetOrganizationByOutCodes2Request request = BaselineGetOrganizationByOutCodes2Request.builder().outCodes(Arrays.asList(code)).build();
        BaselineGetOrganizationByOutCodes2Response res =
                baseDataService.baselineGetOrganizationByOutCodes2(request);
        if (ObjectUtils.isEmpty(res)) {
            return null;
        }
        List<OrganizationSDO> result = res.getResult();
        if (CollectionUtils.isEmpty(result)) {
            return null;
        }
        return result.get(0);
    }

    /**
     * 组装查询参数
     *
     * @param loadPlanReachCorrectionRequest
     * @param combinationItemOutIds
     * @return
     */
    public PlatformCustomerGroupRequest coverPlatformCustomerGroupRequest(LoadPlanReachCorrectionRequest loadPlanReachCorrectionRequest, List<String> combinationItemOutIds) {
        PlatformCustomerGroupRequest loadListPageQueryRequest = new PlatformCustomerGroupRequest();

        loadListPageQueryRequest.setPlatformCodes(loadPlanReachCorrectionRequest.getPlatformCodes());
        //loadListPageQueryRequest.setPlatformCodes(loadPlanReachCorrectionRequest.getPlatformCodes());

        loadListPageQueryRequest.setStartTime(DomUtil.getFirstDayDateOfMonth(DateUtils.parse(loadPlanReachCorrectionRequest.getTime().get(0))));
        loadListPageQueryRequest.setEndTime(DomUtil.getLastDayOfMonth(DateUtils.parse(loadPlanReachCorrectionRequest.getTime().get(1))));

        loadListPageQueryRequest.setPlatformNullId(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID());

        if (!CollectionUtils.isEmpty(combinationItemOutIds)) {
            // 货品 id 转换 ouiid
            // List<String> scItemIds = loadPlanReachCorrectionRequest.getGoodsId();
            //List<String> scItemOutIds = getOutItemIds(combinationItemIds);
            loadListPageQueryRequest.setOuterIds(combinationItemOutIds);
        }

        loadListPageQueryRequest.setScItemName(loadPlanReachCorrectionRequest.getGoodsName());

        loadListPageQueryRequest.setStart(0);
        loadListPageQueryRequest.setLimit(500);
        return loadListPageQueryRequest;
    }

    @NotNull
    private List<String> getOutItemIds(List<String> combinationItemIds) {

        List<ScItemSDO> scItemSDOS = getProductCategorySDO(combinationItemIds, null);
        List<String> scItemOutIds = scItemSDOS.stream().map(ScItemSDO::getOuterId).collect(Collectors.toList());

        return scItemOutIds;
    }

    @NotNull
    private Map<String, String> getOutItemNames(List<String> combinationItemIds) {

        List<ScItemSDO> scItemSDOS = getProductCategorySDO(combinationItemIds, null);
        Map<String, String> collect = scItemSDOS.stream().collect(Collectors.toMap(ScItemSDO::getOuterId, ScItemSDO::getTitle, (v1, v2) -> v1));

        return collect;
    }

    @NotNull
    private Map<String, String> getOutItemNamesByCodes(List<String> outerIds) {

        List<ScItemSDO> scItemSDOS = getProductCategorySDO(null, outerIds);
        Map<String, String> collect = scItemSDOS.stream().collect(Collectors.toMap(ScItemSDO::getOuterId, ScItemSDO::getTitle, (v1, v2) -> v1));

        return collect;
    }

    /**
     * 查询 货品对应的 类目 属性
     *
     * @param scItemIds
     * @return
     */
    public List<ScItemSDO> getProductCategorySDO(List<String> scItemIds, List<String> outerIdList) {

        // 查询 商品
        SearchScItemRequest searchScItemRequest = new SearchScItemRequest();
        int pageNum = 1;
        int pageSize = 999;
        searchScItemRequest.setPageNum(pageNum);
        searchScItemRequest.setPageSize(pageSize);

        Map<String, Object> map = new HashMap<String, Object>() {{
            put("scItemIds", scItemIds);
            put("outerIdList", outerIdList);
        }};

        searchScItemRequest.setSearchReqDTO(map);
        Result<List<ScItemSDO>> listResult = baseDataService.searchScItem(searchScItemRequest);
        if (ObjectUtils.isEmpty(listResult)) {
            return null;
        }
        List<ScItemSDO> result = listResult.getResult();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(result)) {
            return null;
        }
        while (listResult.getTotal() > pageNum * pageSize) {
            pageNum += 1;
            Result<List<ScItemSDO>> listResult1 = baseDataService.searchScItem(searchScItemRequest);
            if (!ObjectUtils.isEmpty(listResult1) && !CollectionUtils.isEmpty(listResult1.getResult())) {
                result.addAll(listResult1.getResult());
            }
        }
        ;

        return result;
    }

    /**
     * 组装页面参数
     *
     * @param fistDays
     * @param middleDays
     * @param lastDays
     * @param planCommerce
     * @param factorySendOrder
     * @param platformNameById
     * @param platformId
     * @param scItemName
     * @return
     */
    private PlanReachCorrection coverPlanReachCorrection(String time, int fistDays, int middleDays, int lastDays, CommerCustomerPlanReport planCommerce, Map<String, Integer> factorySendOrder, Map<String, String> platformNameById, Boolean isExcel, String platformCode, String platformId, String itemOutId, String scItemName) {
        PlanReachCorrection planReachCorrection = new PlanReachCorrection();
        String key = platformCode + "-" + itemOutId;
        //内部平台ID platformId
        platformId = StringUtils.isEmpty(platformId) ? OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID() : platformId;
        planReachCorrection.setPlatformCode(platformId);
        String platformName = StringUtils.isEmpty(platformNameById.get(platformId)) ? OtsApplicationReportSdkConstants.OTHER_PLATFORM_NAME() : platformNameById.get(platformId);
        planReachCorrection.setPlatformName(platformName);
        planReachCorrection.setGoodsId(itemOutId);
        planReachCorrection.setGoodsName(scItemName);


        // 本月下旬 天数
        int leftLastDay = getCurrentMonthLastDay(time) - 20;
        // 上旬 日均*查询上旬天数
        long firstCount = planCommerce.getMonthFirstPlannedQuantity() != null ? DomUtil.divide(planCommerce.getMonthFirstPlannedQuantity(), 10) * fistDays : 0;
        if (fistDays == 10) {
            firstCount = planCommerce.getMonthFirstPlannedQuantity() != null ? planCommerce.getMonthFirstPlannedQuantity() : 0;
        }
        planReachCorrection.setMonthFirstCount(DomUtil.numFormat2(firstCount, isExcel));
        long firstReturnCount = planCommerce.getMonthFirstReturnCount() != null ? DomUtil.divide(planCommerce.getMonthFirstReturnCount(), 10) * fistDays : 0;
        if (fistDays == 10) {
            firstReturnCount = planCommerce.getMonthFirstReturnCount() != null ? planCommerce.getMonthFirstReturnCount() : 0;
        }
        planReachCorrection.setMonthFirstReturnCount(DomUtil.numFormat2(firstReturnCount, isExcel));
        long firstAdjustTotalCount = (planCommerce.getMonthFirstReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthFirstReviseConfirmCount(), 10) * fistDays : 0) - firstReturnCount;
        if (fistDays == 10) {
            firstAdjustTotalCount = (planCommerce.getMonthFirstReviseConfirmCount() != null ? planCommerce.getMonthFirstReviseConfirmCount() : 0) - firstReturnCount;
        }
        planReachCorrection.setMonthFirstAdjustTotalCount(DomUtil.numFormat2(firstAdjustTotalCount, isExcel));
        long firstTaskCount = planCommerce.getMonthFirstReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthFirstReviseConfirmCount(), 10) * fistDays : 0;
        if (fistDays == 10) {
            firstTaskCount = planCommerce.getMonthFirstReviseConfirmCount() != null ? planCommerce.getMonthFirstReviseConfirmCount() : 0;
        }
        planReachCorrection.setMonthFirstTaskCount(DomUtil.numFormat2(firstTaskCount, isExcel));
        // 中旬 日均*查询中旬天数
        long middleCount = planCommerce.getMonthMiddlePlannedQuantity() != null ? DomUtil.divide(planCommerce.getMonthMiddlePlannedQuantity(), 10) * middleDays : 0;
        if (middleDays == 10) {
            middleCount = planCommerce.getMonthMiddlePlannedQuantity() != null ? planCommerce.getMonthMiddlePlannedQuantity() : 0;
        }
        planReachCorrection.setMonthMiddleCount(DomUtil.numFormat2(middleCount, isExcel));
        long middleReturnCount = planCommerce.getMonthMiddleReturnCount() != null ? DomUtil.divide(planCommerce.getMonthMiddleReturnCount(), 10) * middleDays : 0;
        if (middleDays == 10) {
            middleReturnCount = planCommerce.getMonthMiddleReturnCount() != null ? planCommerce.getMonthMiddleReturnCount() : 0;
        }
        planReachCorrection.setMonthMiddleReturnCount(DomUtil.numFormat2(middleReturnCount, isExcel));
        long middleAdjustTotalCount = planCommerce.getMonthMiddleReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthMiddleReviseConfirmCount(), 10) * middleDays - middleReturnCount : 0 - (planCommerce.getMonthMiddleReturnCount() != null ? (planCommerce.getMonthMiddleReturnCount() / 10) * middleDays : 0);
        if (middleDays == 10) {
            middleAdjustTotalCount = planCommerce.getMonthMiddleReviseConfirmCount() != null ? planCommerce.getMonthMiddleReviseConfirmCount() - middleReturnCount : 0 - middleReturnCount;
        }
        planReachCorrection.setMonthMiddleAdjustTotalCount(DomUtil.numFormat2(middleAdjustTotalCount, isExcel));
        long middleTaskCount = planCommerce.getMonthMiddleReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthMiddleReviseConfirmCount(), 10) * middleDays : 0;
        if (middleDays == 10) {
            middleTaskCount = planCommerce.getMonthMiddleReviseConfirmCount() != null ? planCommerce.getMonthMiddleReviseConfirmCount() : 0;
        }
        planReachCorrection.setMonthMiddleTaskCount(DomUtil.numFormat2(middleTaskCount, isExcel));
        // 下旬 日均*查询下旬天数
        long lastCount = planCommerce.getMonthLastPlannedQuantity() != null ? DomUtil.divide(planCommerce.getMonthLastPlannedQuantity(), leftLastDay) * lastDays : 0;
        if (leftLastDay == lastDays) {
            lastCount = planCommerce.getMonthLastPlannedQuantity() != null ? planCommerce.getMonthLastPlannedQuantity() : 0;
        }
        planReachCorrection.setMonthLastCount(DomUtil.numFormat2(lastCount, isExcel));
        long lastReturnCount = planCommerce.getMonthLastReturnCount() != null ? DomUtil.divide(planCommerce.getMonthLastReturnCount(), leftLastDay) * lastDays : 0;
        if (leftLastDay == lastDays) {
            lastReturnCount = planCommerce.getMonthLastReturnCount() != null ? planCommerce.getMonthLastReturnCount() : 0;
        }
        planReachCorrection.setMonthLastReturnCount(DomUtil.numFormat2(lastReturnCount, isExcel));
        long lastAdjustTotalCount = planCommerce.getMonthLastReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthLastReviseConfirmCount(), leftLastDay) * lastDays - lastReturnCount : 0 - lastReturnCount;
        if (leftLastDay == lastDays) {
            lastAdjustTotalCount = planCommerce.getMonthLastReviseConfirmCount() != null ? planCommerce.getMonthLastReviseConfirmCount() - lastReturnCount : 0 - lastReturnCount;
        }
        planReachCorrection.setMonthLastAdjustTotalCount(DomUtil.numFormat2(lastAdjustTotalCount, isExcel));
        long lastTaskCount = planCommerce.getMonthLastReviseConfirmCount() != null ? DomUtil.divide(planCommerce.getMonthLastReviseConfirmCount(), leftLastDay) * lastDays : 0;
        if (leftLastDay == lastDays) {
            lastTaskCount = planCommerce.getMonthLastReviseConfirmCount() != null ? planCommerce.getMonthLastReviseConfirmCount() : 0;
        }
        planReachCorrection.setMonthLastTaskCount(DomUtil.numFormat2(lastTaskCount, isExcel));
        // 工厂直发订单
        Integer integer = 0;
        //String key = planReachCorrection.getPlatformCode() + "-" + planReachCorrection.getGoodsId();
        if (!ObjectUtils.isEmpty(factorySendOrder) && !ObjectUtils.isEmpty(factorySendOrder.get(key))) {
            integer = factorySendOrder.get(key);
        }
        planReachCorrection.setFactorySendingOrder(integer.toString());
        // 计划剩余量=上中下旬计划调整后-工厂直发订单
        long planRemaining = firstTaskCount + middleTaskCount + lastTaskCount;
        long planRemainingCount = (planRemaining - integer) >= 0 ? planRemaining - integer : 0;
        planReachCorrection.setPlanRemainingCount(DomUtil.numFormat2(planRemainingCount, isExcel));
        // 达成率=（工厂直发订单/计划调整后）*100%
        double planReachCorrectionDivide;
        if (planRemaining == 0) {
            planReachCorrectionDivide = 0D;
        } else {
            planReachCorrectionDivide = integer == 0 ? 0 : divide(Double.valueOf(planReachCorrection.getFactorySendingOrder()), (double) planRemaining, 4);
        }
        planReachCorrection.setFinishRatio((mul(planReachCorrectionDivide, 100D, 2)) + "%");
        // 调整占比=（上中下旬计划调整量/上中下旬计划任务量）*100%
        long adjustTotalCount = firstAdjustTotalCount + middleAdjustTotalCount + lastAdjustTotalCount;
        long returnCount = firstReturnCount + middleReturnCount + lastReturnCount;
        double returnCountDivide;
        if (adjustTotalCount == 0) {
            returnCountDivide = 0D;
        } else {
            returnCountDivide = returnCount == 0 ? 1 : (divide((double) adjustTotalCount, (double) returnCount, 4));
        }
        planReachCorrection.setAdjustmentRatio((mul(returnCountDivide, 100D, 2)) + "%");

        return planReachCorrection;
    }

    /**
     * 提供（相对）精确的除法运算。 当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入。
     *
     * @param dividend 被除数
     * @param divisor  除数
     * @param scale    表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static Double divide(Double dividend, Double divisor, Integer scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(dividend));
        BigDecimal b2 = new BigDecimal(Double.toString(divisor));
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     * @Title：mul
     * @Description: 提供精确的乘法运算。
     * @author shaojian.yu
     * @date 2015年11月9日 下午5:47:51
     */
    private double mul(double v1, double v2, int scale) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return round(b1.multiply(b2).doubleValue(), scale);
    }

    /**
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     * @Title：round
     * @Description: 提供精确的小数位四舍五入处理。
     * @author shaojian.yu
     * @date 2015年11月9日 下午5:49:13
     */
    private double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException(
                    "The   scale   must   be   a   positive   integer   or   zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 获取某月天数
     *
     * @return
     */
    public static int getCurrentMonthLastDay(String time) {
        Calendar a = Calendar.getInstance();

        a.setTime(DateUtils.formatString2Date(time, DateUtils.DATE_FORMAT));

        //把日期设置为当月第一天
        a.set(Calendar.DATE, 1);

        //日期回滚一天，也就是最后一天
        a.roll(Calendar.DATE, -1);

        int maxDate = a.get(Calendar.DATE);

        return maxDate;

    }

    // 判断两个日期是否跨月
    private boolean equalsMonth(Date date1, Date date2) {

        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        int year1 = calendar1.get(Calendar.YEAR);
        int year2 = calendar2.get(Calendar.YEAR);
        int month1 = calendar1.get(Calendar.MONTH);
        int month2 = calendar2.get(Calendar.MONTH);
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);

    }

    public Result<List<Pair<String, String>>> getEfficientPlatGoodsCombination(List<String> getPlatformCodes, List<String> scItems, List<String> times, String orgId, String goodsName) {
        List<Pair<String, String>> result = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(ALLOCATE_ORDER_DETAIL_REPORT_FTOB);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(getPlatformCodes)) {
            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(CUSTOMER_COMMERCE_PLATFORM + KEYWORD, getPlatformCodes);
            boolQueryBuilder.must(multiQuery);
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(scItems)) {
            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(SUB_SC_ITEM_CODE + KEYWORD, scItems);
            boolQueryBuilder.must(multiQuery);
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(goodsName)) {
            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(SC_ITEM_TITLE + KEYWORD, goodsName);
            boolQueryBuilder.must(multiQuery);
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(times)) {
            RangeQueryBuilder multiQuery = QueryBuilders.rangeQuery(MAIN_CREATE_TIME).gte(DateUtils.parse(times.get(0)).getTime())
                    .lte(DateUtils.getLatestTime(DateUtils.parse(times.get(1))).getTime());
            boolQueryBuilder.filter(multiQuery);
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(orgId)) {
            TermQueryBuilder singleQuery = QueryBuilders.termQuery(MAIN_APPLY_ORG_ID + KEYWORD, orgId);
            boolQueryBuilder.must(singleQuery);
        }

        TermsQueryBuilder warehouseTypes = QueryBuilders.termsQuery(SHIP_WAREHOUSE_TYPE, Arrays.asList(2, 5));
        TermQueryBuilder isDtc = QueryBuilders.termQuery(MAIN_IS_D_T_C, 1);
        TermQueryBuilder type = QueryBuilders.termQuery(MAIN_TYPE, AllocateOrderTypeEnum.HEADQUARTER_SALES.getType());
        boolQueryBuilder.must(warehouseTypes);
        boolQueryBuilder.must(isDtc);
        boolQueryBuilder.must(type);

        Script script = new Script("doc['sub_sc_item_code.keyword'].value +','+ doc['customer_commerce_platform.keyword'].value");
        CardinalityAggregationBuilder cardPlatItem = AggregationBuilders.cardinality(CARDINALITY_ITEM_PLATFORM).script(script);
        searchSourceBuilder.aggregation(cardPlatItem);

        TermsAggregationBuilder termsBuilder = AggregationBuilders.terms(CUSTOMER_COMMERCE_PLATFORM).field(CUSTOMER_COMMERCE_PLATFORM + KEYWORD)
                .order(BucketOrder.key(Boolean.TRUE)).size(200);
        termsBuilder.subAggregation(AggregationBuilders.terms(SUB_SC_ITEM_CODE).field(SUB_SC_ITEM_CODE + KEYWORD)
                .size(Integer.MAX_VALUE)).order(BucketOrder.key(Boolean.TRUE));

        searchSourceBuilder.aggregation(termsBuilder);
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(boolQueryBuilder);

        searchRequest.types("_doc");
        searchRequest.source(searchSourceBuilder);
        log.info("ES 分组分页查询入参:" + JSON.toJSONString(searchRequest));
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, ElasticSearchClientFactory.getCommonOptions());
        } catch (IOException e) {
            log.error("查询ES错误:{}", e);
            e.printStackTrace();
        }
        Aggregations aggregations = searchResponse.getAggregations();
        Cardinality cardinality = aggregations.get(CARDINALITY_ITEM_PLATFORM);
        long total = cardinality.getValue();
        Terms terms = aggregations.get(CUSTOMER_COMMERCE_PLATFORM);
        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        if (org.apache.commons.collections4.CollectionUtils.isEmpty(buckets)) {
            return Result.listSuccess(new ArrayList<>(), 0);
        }

        for (Terms.Bucket bucket : buckets) {
            String platFormCode = bucket.getKeyAsString();
            Map<String, Aggregation> asMap = bucket.getAggregations().getAsMap();
            if (null != asMap.get(SUB_SC_ITEM_CODE)) {
                Object o = JSONObject.toJSON(asMap.get(SUB_SC_ITEM_CODE));
                JSONObject jsonObject = JSONObject.parseObject(o.toString());
                JSONArray itemArray = jsonObject.getJSONArray("buckets");
                if (org.apache.commons.collections4.CollectionUtils.isEmpty(itemArray)) {
                    continue;
                }
                for (Object item : itemArray) {
                    String outItemId = String.valueOf(JSONObject.parseObject(JSON.toJSON(item).toString()).get("key"));
                    result.add(Pair.of(platFormCode, outItemId));
                }
            }
        }


        return Result.listSuccess(result, total);
    }

    public Result<List<Pair<String, String>>> getEmptyPlatGoodsCombination(List<String> getPlatformCodes, List<String> scItems, List<String> times, String orgId, String goodsName) {
        List<Pair<String, String>> result = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(ALLOCATE_ORDER_DETAIL_REPORT_FTOB);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(getPlatformCodes)&&getPlatformCodes.contains(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID())) {
//            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(CUSTOMER_COMMERCE_PLATFORM + KEYWORD, getPlatformCodes);
            ExistsQueryBuilder existsQueryBuilder = QueryBuilders.existsQuery(CUSTOMER_COMMERCE_PLATFORM);
            boolQueryBuilder.mustNot(existsQueryBuilder);
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(scItems)) {
            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(SUB_SC_ITEM_CODE + KEYWORD, scItems);
            boolQueryBuilder.must(multiQuery);
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(goodsName)) {
            TermsQueryBuilder multiQuery = QueryBuilders.termsQuery(SC_ITEM_TITLE + KEYWORD, goodsName);
            boolQueryBuilder.must(multiQuery);
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(times)) {
            RangeQueryBuilder multiQuery = QueryBuilders.rangeQuery(MAIN_CREATE_TIME).gte(DateUtils.parse(times.get(0)).getTime())
                    .lte(DateUtils.getLatestTime(DateUtils.parse(times.get(1))).getTime());
            boolQueryBuilder.filter(multiQuery);
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(orgId)) {
            TermQueryBuilder singleQuery = QueryBuilders.termQuery(MAIN_APPLY_ORG_ID + KEYWORD, orgId);
            boolQueryBuilder.must(singleQuery);
        }

        TermsQueryBuilder warehouseTypes = QueryBuilders.termsQuery(SHIP_WAREHOUSE_TYPE, Arrays.asList(2, 5));
        TermQueryBuilder isDtc = QueryBuilders.termQuery(MAIN_IS_D_T_C, 1);
        TermQueryBuilder type = QueryBuilders.termQuery(MAIN_TYPE, AllocateOrderTypeEnum.HEADQUARTER_SALES.getType());
        boolQueryBuilder.must(warehouseTypes);
        boolQueryBuilder.must(isDtc);
        boolQueryBuilder.must(type);

        Script script = new Script("doc['sub_sc_item_code.keyword'].value");
        CardinalityAggregationBuilder cardPlatItem = AggregationBuilders.cardinality(CARDINALITY_ITEM_PLATFORM).script(script);
        searchSourceBuilder.aggregation(cardPlatItem);

//        TermsAggregationBuilder termsBuilder = AggregationBuilders.terms(CUSTOMER_COMMERCE_PLATFORM).field(CUSTOMER_COMMERCE_PLATFORM + KEYWORD)
//                .order(BucketOrder.key(Boolean.TRUE)).size(200);
        TermsAggregationBuilder termsBuilder = AggregationBuilders.terms(SUB_SC_ITEM_CODE).field(SUB_SC_ITEM_CODE + KEYWORD)
                .size(Integer.MAX_VALUE).order(BucketOrder.key(Boolean.TRUE));

        searchSourceBuilder.aggregation(termsBuilder);
        searchSourceBuilder.size(0);
        searchSourceBuilder.query(boolQueryBuilder);

        searchRequest.types("_doc");
        searchRequest.source(searchSourceBuilder);
        log.info("ES 分组分页查询入参:" + JSON.toJSONString(searchRequest));
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, ElasticSearchClientFactory.getCommonOptions());
        } catch (IOException e) {
            log.error("查询ES错误:{}", e);
            e.printStackTrace();
        }
        Aggregations aggregations = searchResponse.getAggregations();
        Cardinality cardinality = aggregations.get(CARDINALITY_ITEM_PLATFORM);
        long total = cardinality.getValue();
        Terms terms = aggregations.get(SUB_SC_ITEM_CODE);
        List<? extends Terms.Bucket> buckets = terms.getBuckets();

        if (org.apache.commons.collections4.CollectionUtils.isEmpty(buckets)) {
            return Result.listSuccess(new ArrayList<>(), 0);
        }

        for (Terms.Bucket bucket : buckets) {
            String scItemOutCode = bucket.getKeyAsString();
            result.add(Pair.of(OtsApplicationReportSdkConstants.OTHER_PLATFORM_ID(), scItemOutCode));
            }

        return Result.listSuccess(result, total);
    }

}
